
function Connection(canvas, from, to, options){
  this.canvas = canvas;
  this.from = from;
  this.to = to;
  this.lineColor = '#000';
  this.path = null;
  this.arrow = null;
  this.arrowSize = 5;
  if(options){
    if(options.lineColor){
      this.lineColor = options.lineColor;
    }
    if(options.arrowSize){
      this.arrowSize = options.arrowSize;
    }
  }
  this.update();
}

Connection.prototype.update = function(){
  var bb1 = this.from.getBBox();
  var bb2 = this.to.getBBox();
  var p = [{
    x: bb1.x + bb1.width / 2, 
    y: bb1.y - 1
  },{
    x: bb1.x + bb1.width / 2, 
    y: bb1.y + bb1.height + 1
  },{
    x: bb1.x - 1, 
    y: bb1.y + bb1.height / 2
  },{
    x: bb1.x + bb1.width + 1, 
    y: bb1.y + bb1.height / 2
  },{
    x: bb2.x + bb2.width / 2, 
    y: bb2.y - 1
  },{
    x: bb2.x + bb2.width / 2, 
    y: bb2.y + bb2.height + 1
  },{
    x: bb2.x - 1, 
    y: bb2.y + bb2.height / 2
  },{
    x: bb2.x + bb2.width + 1, 
    y: bb2.y + bb2.height / 2
  }];

  var d = {};
  var dis = [];
  for (var i = 0; i < 4; i++) {
    for (var j = 4; j < 8; j++) {
      var dx = Math.abs(p[i].x - p[j].x),
      dy = Math.abs(p[i].y - p[j].y);
      if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
        dis.push(dx + dy);
        d[dis[dis.length - 1]] = [i, j];
      }
    }
  }
  if (dis.length == 0) {
    var res = [0, 4];
  } else {
    res = d[Math.min.apply(Math, dis)];
  }
  var x1 = p[res[0]].x,
  y1 = p[res[0]].y,
  x4 = p[res[1]].x,
  y4 = p[res[1]].y;
  dx = Math.max(Math.abs(x1 - x4) / 2, 10);
  dy = Math.max(Math.abs(y1 - y4) / 2, 10);
  var x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3),
  y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3),
  x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3),
  y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3);
  var path = "M " +  x1.toFixed(3) + " " + y1.toFixed(3) + " C" +  x2 + " " +
  y2 + " " + x3 + " " + y3 + " " + x4.toFixed(3) + " " + y4.toFixed(3);

  if(this.path){
    this.path.attr({
      path: path
    });
  }else{
    this.path = this.canvas.path(path).attr({
      stroke: this.lineColor, 
      fill: "none"
    });
  }
  
  var pt = this.path.getPointAtLength(this.path.getTotalLength() - 5);
  var angle = Math.atan2(pt.x-x4,y4-pt.y);
  angle = (angle / (2 * Math.PI)) * 360;
  var path2 = "M" + x4 + " " + y4 + " L" + (x4 - 5) + " " + (y4 - 5) + " L" + (x4 - 5) + " " + (y4 + 5) + " L" + x4 + " " + y4;

  if(this.arrow){
    this.arrow.remove();
  }
  this.arrow = this.canvas.path(path2).attr({
    stroke: this.lineColor, 
    fill: "none"
  }).rotate((90+angle),x4,y4);
}
